/*
 * fagag.c
 *
 *  Created on: May 3, 2012
 *      Author: root
 */

#include    "unp.h"
#include    "unpthread.h"
#include    "clients.h"

#define IDSIZE 128

void str_service(Client* client);
static void *doit(void *);
void serv_parsing(Client* client, char* str, int* check);

pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t freeList_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t clientList_mutex = PTHREAD_MUTEX_INITIALIZER;

char* LOG_STRING = "230 User logged in\r\n\r\n";
char* ACK_STRING = "200 OK\r\n\r\n";
char* QUIT_STRING = "221 Service closing\r\n\r\n";
char* SYNTAX_ERR_STRING = "500 Syntax error, command unrecognized\r\n\r\n";
char* LOG_ERR_STRING = "530 Not logged in\r\n\r\n";

static int user_count = 0;
static Client* user;

int main(int argc, char **argv) {
	int listenfd, sockfd; //*iptr;
	pthread_t tid;
	socklen_t addrlen, len;
	struct sockaddr *cliaddr;

	if (argc == 2)
		listenfd = Tcp_listen(NULL, argv[1], &addrlen);
	else if (argc == 3)
		listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
	else
		err_quit("usage: tcpserv01 [ <host> ] <service or port>");

	printf("Server ON\n");

	for (;;) {
		len = addrlen;

		cliaddr = malloc(addrlen);

		sockfd = accept(listenfd, cliaddr, &len);

		pthread_mutex_lock(&freeList_mutex);
		pthread_mutex_lock(&clientList_mutex);
		user = createClient(sockfd);
		pthread_mutex_unlock(&freeList_mutex);
		pthread_mutex_unlock(&clientList_mutex);

		user->connfd = sockfd;
		user->addr = cliaddr;

		strcpy(user->address, inet_ntoa(user->addr->sin_addr));

		pthread_create(&tid, NULL, &doit, user);
	}

	return 0;
}

static void* doit(void *arg) {

	Client* client;

	client = ((Client *) arg);

	pthread_detach(pthread_self());

	str_service(client);
	close(client->connfd);

	return (NULL);

}

void str_service(Client* client) {

	int n = 1;
	int check_end = 0;
	int* check = &check_end;
	ReadBuffer* rbuf;
	char response[MAXLINE];
	rbuf = createRbuf(MAXLINE);

	char buf[MAXLINE];

	//printf("user connfd : %d\n", client->connfd);

	while (check_end == 0) {
		if ((n = readBuf(rbuf, client->connfd)) < 0)
			err_sys("read error\n");
		while (getMessage(rbuf, response, MAXLINE) != NULL) {
			printf("<---%s\n", response);
			serv_parsing(client, response, check);
		}
		if (n == 0) {
			sprintf(buf, "QUIT\r\n\r\n");
			serv_parsing(client, buf, check);
		}
	}
}

void serv_parsing(Client* client, char* str, int* check) {

	Client *cli;
	Client *rcv_cli;
	Client *send_cli;

	char buf[MAXLINE];
	char* p;
	int n;

	char word1[MAXLINE];
	char word2[MAXLINE];
	char word3[MAXLINE];
	char word4[MAXLINE];
	char word5[MAXLINE];
	char word6[MAXLINE];

	char msg[MAXLINE];

	char file_name[MAXLINE];
	char fromid[IDSIZE];
	char toid[IDSIZE];

	memset(file_name, 0x00, MAXLINE);
	memset(fromid, 0x00, IDSIZE);
	memset(toid, 0x00, IDSIZE);

	memset(msg, 0x00, MAXLINE);
	memset(word1, 0x00, MAXLINE);
	memset(word2, 0x00, MAXLINE);
	memset(word3, 0x00, MAXLINE);
	memset(word4, 0x00, MAXLINE);
	memset(word5, 0x00, MAXLINE);
	memset(word6, 0x00, MAXLINE);

	n = sscanf(str, "%s %s %s %s %s %s", word1, word2, word3, word4, word5,
			word6);

	if (!strcmp(word1, "USER") && (client->log == 0) && (n == 2)) {

		pthread_mutex_lock(&clientList_mutex);
		if (findClient(word2) == NULL) { ///////////////////// LCOK
			pthread_mutex_unlock(&clientList_mutex);

			strcpy(client->id, word2);
			client->log = 1;

			pthread_mutex_lock(&user_count_mutex);
			user_count++;
			printf("connected %d people, %s is connect\n", user_count,
					client->id);
			pthread_mutex_unlock(&user_count_mutex);

			sprintf(msg, "%s", LOG_STRING);
			writen(client->connfd, msg, strlen(msg));
			printf("--->%s", msg);
			printf("User Login\n");
			printf("[%d] ID : %s\n", client->connfd, client->id);
			printf("address : %s\n", client->address);
			printf("socket  : %d\n", client->connfd);

		} else {
			// LOG error (same ID)
			sprintf(msg, "%s", SYNTAX_ERR_STRING);
			writen(client->connfd, msg, strlen(msg));
			printf("--->%s\n", msg);
		}
	} else if ((!strcmp(word1, "QUIT"))
			&& ((client->log == 0) || (client->log == 1)) && (n == 1)) {
		sprintf(msg, "%s", QUIT_STRING);
		writen(client->connfd, msg, strlen(msg));
		printf("--->%s\n", msg);
		printf("disconnected %s\n", client->id);

		pthread_mutex_lock(&user_count_mutex);
		if (client->log == 1) {
			user_count--;
			printf("connected %d people, %s is disconnected\n", user_count,
					client->id);
		}
		if (client->log == 0) {
			printf("connected %d people, not login user is disconnected\n",
					user_count);
		}
		pthread_mutex_unlock(&user_count_mutex);

		client->log = 0;
		*check = 1;

		pthread_mutex_lock(&freeList_mutex);
		pthread_mutex_lock(&clientList_mutex);
		destroyClient(client);
		pthread_mutex_unlock(&freeList_mutex);
		pthread_mutex_unlock(&clientList_mutex);

		Close(client->connfd);
	}

	else if ((!strcmp(word1, "WHO")) && (client->log == 1) && (n == 1)) {
		strcat(msg, "210 OK\r\n");

		for (cli = user; cli != NULL; cli = cli->next) {
			strcat(msg, getUser(cli));
			strcat(msg, " ");
		}
		strcat(msg, "\r\n\r\n");

		writen(client->connfd, msg, strlen(msg));
		printf("--->%s\n", msg);

	} else if ((!strcmp(word1, "FROM")) && (client->log == 1)) {

		strcpy(toid, word4);
		strcpy(fromid, word2);

		p = space_remover(buf, str, strlen(str));
		p = space_remover(buf, p, strlen(p));
		p = space_remover(buf, p, strlen(p));
		p = space_remover(buf, p, strlen(p));
		p = space_remover2(p, strlen(p));

		pthread_mutex_lock(&clientList_mutex);
		rcv_cli = findClient(toid);
		pthread_mutex_unlock(&clientList_mutex);
		if (rcv_cli != NULL) {

			sprintf(msg, "299 Message delivered\r\nFROM %s TO %s\r\n%s",
					fromid, toid, p);
			writen(rcv_cli->connfd, msg, strlen(msg));
			printf("--->%s\n", msg);

			writen(client->connfd, ACK_STRING, strlen(ACK_STRING));
			printf("--->%s\n", ACK_STRING);

		} else if (!strcmp(toid, "all")) {
			sprintf(msg, "299 Message delivered\r\nFROM %s TO %s\r\n%s",
					fromid, toid, p);
			for (cli = user; cli != NULL; cli = cli->next) {
				if ((cli->log == 1) && (strcmp(cli->id, fromid) != 0)) {
					writen(cli->connfd, msg, strlen(msg));
					printf("--->%s\n", msg);
				}
			}
			if (user_count > 1) {
				writen(client->connfd, ACK_STRING, strlen(ACK_STRING));
				printf("--->%s\n", ACK_STRING);
			} else {
				writen(client->connfd, SYNTAX_ERR_STRING,
						strlen(SYNTAX_ERR_STRING));
				printf("--->%s\n", SYNTAX_ERR_STRING);
			}
		} else {
			// User not in group
			writen(client->connfd, SYNTAX_ERR_STRING,
					strlen(SYNTAX_ERR_STRING));
			printf("--->%s\n", SYNTAX_ERR_STRING);
		}

	} else if ((!strcmp(word1, "SEND")) && (client->log == 1) && (n == 6)) {
		strcpy(toid, word6);
		strcpy(fromid, word4);
		strcpy(file_name, word2);

		pthread_mutex_lock(&clientList_mutex);
		rcv_cli = findClient(toid);
		pthread_mutex_unlock(&clientList_mutex);

		if (rcv_cli != NULL) {

			sprintf(msg,
					"298 File transfer attempt\r\nSEND %s FROM %s TO %s\r\n\r\n",
					file_name, fromid, toid);

			writen(rcv_cli->connfd, msg, strlen(msg));
			printf("--->%s\n", msg);
		} else {
			// User not in group
			writen(client->connfd, SYNTAX_ERR_STRING,
					strlen(SYNTAX_ERR_STRING));
			printf("--->%s\n", SYNTAX_ERR_STRING);
		}

	} else if ((!strcmp(word1, "ACCEPT")) && (client->log == 1) && (n == 6)) {
		strcpy(toid, word6);
		strcpy(fromid, word4);
		strcpy(file_name, word2);
		pthread_mutex_lock(&clientList_mutex);
		rcv_cli = findClient(toid);
		pthread_mutex_unlock(&clientList_mutex);


		pthread_mutex_lock(&clientList_mutex);
		send_cli = findClient(fromid);
		pthread_mutex_unlock(&clientList_mutex);

		if (send_cli != NULL) {

			sprintf(msg,
					"227 %s Ready to receive file\r\nACCEPT %s FROM %s TO %s\r\n\r\n",
					inet_ntoa(rcv_cli->addr->sin_addr), file_name, fromid,
					toid);

			writen(send_cli->connfd, msg, strlen(msg));
			printf("--->%s\n", msg);

			writen(client->connfd, ACK_STRING, strlen(ACK_STRING));
			printf("--->%s\n", ACK_STRING);

		} else {
			// User not in group
			writen(client->connfd, SYNTAX_ERR_STRING,
					strlen(SYNTAX_ERR_STRING));
			printf("--->%s\n", SYNTAX_ERR_STRING);
		}

	} else if ((!strcmp(word1, "REJECT")) && (client->log == 1) && (n == 6)) {
		strcpy(toid, word6);
		strcpy(fromid, word4);
		strcpy(file_name, word2);

		pthread_mutex_lock(&clientList_mutex);
		rcv_cli = findClient(toid);
		pthread_mutex_unlock(&clientList_mutex);
		if (rcv_cli  != NULL) {

			sprintf(msg, "425 Rejected\r\nREJECT %s FROM %s TO %s\r\n\r\n",
					file_name, fromid, toid);

			writen(rcv_cli->connfd, msg, strlen(msg));
			printf("--->%s\n", msg);
		} else {
			// User not in group
			writen(client->connfd, SYNTAX_ERR_STRING,
					strlen(SYNTAX_ERR_STRING));
			printf("--->%s\n", SYNTAX_ERR_STRING);
		}
	} else if (client->log == 0) {
		writen(client->connfd, LOG_ERR_STRING, strlen(LOG_ERR_STRING));
		printf("--->%s\n", LOG_ERR_STRING);

	} else { // syntax error
		writen(client->connfd, SYNTAX_ERR_STRING, strlen(SYNTAX_ERR_STRING));
		printf("--->%s\n", SYNTAX_ERR_STRING);
	}

}
